package cn.iocoder.yudao.module.trade.aftersale.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.basic.dao.repository.SerialNoRedisRepository;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.exception.KnownServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.region.RegionUtils;
import cn.iocoder.yudao.framework.region.enums.RegionDataSet;
import cn.iocoder.yudao.framework.thirdparty.zxhx.ZXHXApiClientFactory;
import cn.iocoder.yudao.framework.thirdparty.zxhx.dto.ZXHXAfterSaleSubmitReqDTO;
import cn.iocoder.yudao.framework.thirdparty.zxhx.dto.ZXHXAfterSaleSubmitRespDTO;
import cn.iocoder.yudao.framework.thirdparty.zxhx.dto.ZXHXExpressItemRespDTO;
import cn.iocoder.yudao.framework.thirdparty.zxhx.dto.ZXHXOrderSubmitRespDTO;
import cn.iocoder.yudao.framework.thirdparty.zxhx.enums.ZXHXAfterSaleType;
import cn.iocoder.yudao.framework.util.TransactionUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.api.infrastructure.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.api.infrastructure.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.api.pay.refund.PayRefundApi;
import cn.iocoder.yudao.module.api.pay.refund.dto.PayRefundCreateDTO;
import cn.iocoder.yudao.module.api.pay.refund.enums.UnifiedRefundStatusEnum;
import cn.iocoder.yudao.module.api.pay.refund.vo.PayRefundVO;
import cn.iocoder.yudao.module.api.promotion.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.api.promotion.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.api.promotion.combination.enums.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.api.shop.admin.ShopUserApi;
import cn.iocoder.yudao.module.api.shop.admin.dto.ShopAdminRespDTO;
import cn.iocoder.yudao.module.api.trade.aftersale.enums.AfterSaleOperateTypeEnum;
import cn.iocoder.yudao.module.api.trade.aftersale.enums.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.api.trade.aftersale.enums.AfterSaleTypeEnum;
import cn.iocoder.yudao.module.api.trade.aftersale.enums.AfterSaleWayEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeNotifySceneEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.aftersale.bo.AfterSaleLogCreateReqBO;
import cn.iocoder.yudao.module.trade.aftersale.convert.AfterSaleConvert;
import cn.iocoder.yudao.module.trade.aftersale.dal.dataobject.AfterSaleDO;
import cn.iocoder.yudao.module.trade.aftersale.dal.mysql.AfterSaleMapper;
import cn.iocoder.yudao.module.trade.aftersale.vo.*;
import cn.iocoder.yudao.module.trade.delivery.dal.dataobject.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.delivery.service.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderDO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderLogDO;
import cn.iocoder.yudao.module.trade.order.service.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.order.service.TradeOrderUpdateService;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.api.trade.ConfigConstants.REFUND_ORDER_NO_PREFIX;
import static cn.iocoder.yudao.module.api.trade.ErrorCodeConstants.*;

/**
 * 售后订单 Service 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@Service
@Validated
public class AfterSaleServiceImpl implements AfterSaleService {

    @Resource
    private AfterSaleMapper tradeAfterSaleMapper;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private AfterSaleLogService afterSaleLogService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderUpdateService tradeOrderUpdateService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderQueryService tradeOrderQueryService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private DeliveryExpressService deliveryExpressService;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private CombinationRecordApi combinationRecordApi;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private PayRefundApi payRefundApi;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private ShopUserApi shopUserApi;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private NotifyMessageSendApi notifyMessageSendApi;

    @Resource
    private SerialNoRedisRepository serialNoRedisRepository;

    @Override
    public PageResult<AfterSaleDO> getAfterSalePage(AfterSalePageReqVO pageReqVO) {
        return tradeAfterSaleMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<AfterSaleDO> getAfterSalePage(Long userId, AppAfterSalePageReqVO pageParam) {
        return tradeAfterSaleMapper.selectPage(userId, pageParam);
    }

    @Override
    @DataPermission(enable = false)
    public PageResult<AfterSaleDO> getSellerAfterSalePage(Long shopId, AppAfterSalePageReqVO pageParam) {
        return tradeAfterSaleMapper.selectPageShopId(shopId, pageParam);
    }

    @Override
    public AfterSaleDO getAfterSale(Long userId, Long id) {
        return tradeAfterSaleMapper.selectByIdAndUserId(id, userId);
    }

    @Override
    public List<AfterSaleDO> getAfterSaleByOrderId(Long userId, Long orderId) {
        return tradeAfterSaleMapper.selectByOrderIdAndUserId(orderId, userId);
    }

    @Override
    @DataPermission(enable = false)
    public AfterSaleDO getSellerAfterSale(Long shopId, Long id) {
        return tradeAfterSaleMapper.selectByIdAndShopId(id, shopId);
    }

    @Override
    public List<AfterSaleDO> getSellerAfterSaleByOrderId(Long shopId, Long orderId) {
        return tradeAfterSaleMapper.selectByOrderIdAndShopId(orderId, shopId);
    }

    @Override
    public AfterSaleDO getAfterSale(Long id) {
        return tradeAfterSaleMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) {
        // 第一步，前置校验
        List<TradeOrderItemDO> tradeOrderItems = validateOrderApplicable(userId, createReqVO);
        Assertions.notEmpty(tradeOrderItems, ORDER_ITEM_NOT_FOUND.getMsg());
        // 第二步，存储售后订单
        Long afterSaleId = null;
        for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) {
            AfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem);
            if (afterSaleId == null) {
                afterSaleId = afterSale.getId();
            }
        }
        return afterSaleId;
    }

    /**
     * 校验交易订单项是否可以申请售后
     *
     * @param userId      用户编号
     * @param createReqVO 售后创建信息
     * @return 交易订单项
     */
    private List<TradeOrderItemDO> validateOrderApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) {
        List<TradeOrderItemDO> items = new ArrayList<>();
        TradeOrderDO order;
        if (createReqVO.getOrderId() != null && createReqVO.getOrderId() > 0) {
            order = tradeOrderQueryService.getOrder(userId, createReqVO.getOrderId());
            Assertions.notNull(order, ORDER_NOT_FOUND.getMsg());
            items = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
            Integer payPrice = 0;
            for (TradeOrderItemDO item : items) {
                // 已申请售后，不允许再发起售后申请
                if (!Objects.equals(item.getAfterSaleStatus(), AfterSaleStatusEnum.NONE.getStatus())) {
                    throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED);
                }
                payPrice += item.getPayPrice();
            }
            // 申请的退款金额，不能超过订单实付款
            if (createReqVO.getRefundPrice() != null && createReqVO.getRefundPrice() > payPrice) {
                throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR, MoneyUtils.fenToYuanStr(payPrice));
            }
        } else {
            // 校验订单项存在
            TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(userId, createReqVO.getOrderItemId());
            if (orderItem == null) {
                throw exception(ORDER_ITEM_NOT_FOUND);
            }
            // 已申请售后，不允许再发起售后申请
            if (!Objects.equals(orderItem.getAfterSaleStatus(), AfterSaleStatusEnum.NONE.getStatus())) {
                throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED);
            }
            // 申请的退款金额，不能超过订单实付款
            if (createReqVO.getRefundPrice() != null && createReqVO.getRefundPrice() > orderItem.getPayPrice()) {
                throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR, MoneyUtils.fenToYuanStr(orderItem.getPayPrice()));
            }
            order = tradeOrderQueryService.getOrder(userId, orderItem.getOrderId());
            Assertions.notNull(order, ORDER_NOT_FOUND.getMsg());
            items.add(orderItem);
        }
        // 已取消，无法发起售后
        if (TradeOrderStatusEnum.isClosed(order.getStatus())) {
            throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED);
        }
        // 未支付，无法发起售后
        if (!TradeOrderStatusEnum.havePaid(order.getStatus())) {
            throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID);
        }
        // 如果是【退货退款】的情况，需要额外校验是否发货
        if (createReqVO.getWay().equals(AfterSaleWayEnum.RETURN_AND_REFUND.getWay())
            && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) {
            throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED);
        }
        // 超过一定时间，不允许发起售后
        int days = 30;
        if (order.getPayTime() != null && order.getPayTime().plusDays(days).isBefore(LocalDateTime.now())) {
            throw new KnownServiceException("订单已超过" + days + "天，无法申请售后");
        }
        // 如果是拼团订单，则进行中不允许发起售后
        if (TradeOrderTypeEnum.isCombination(order.getType())) {
            CombinationRecordRespDTO combinationRecord = combinationRecordApi.getCombinationRecordByOrderId(order.getUserId(), order.getId());
            if (combinationRecord != null && CombinationRecordStatusEnum.isInProgress(combinationRecord.getStatus())) {
                throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_COMBINATION_IN_PROGRESS);
            }
        }
        return items;
    }

    private AfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO orderItem) {
        // 创建售后单
        AfterSaleDO afterSale = AfterSaleConvert.INSTANCE.convert(createReqVO, orderItem);
        afterSale.setId(null);
        afterSale.setPayPrice(orderItem.getPayPrice());
        if (afterSale.getRefundPrice() == null || afterSale.getRefundPrice() <= 0) {
            afterSale.setRefundPrice(orderItem.getPayPrice());
        }
        afterSale.setNo(serialNoRedisRepository.generateNo(REFUND_ORDER_NO_PREFIX));
        afterSale.setStatus(AfterSaleStatusEnum.APPLY.getStatus());
        // 标记是售中还是售后
        TradeOrderDO order = tradeOrderQueryService.getOrder(orderItem.getUserId(), orderItem.getOrderId());
        afterSale.setShopId(order.getShopId());
        afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水，方便后续检索
        afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus())
                ? AfterSaleTypeEnum.AFTER_SALE.getType() : AfterSaleTypeEnum.IN_SALE.getType());
        afterSale.setSupplyName(order.getSupplyName());
        afterSale.setSupplyRelatedOrders(order.getSupplyRelatedOrders());
        afterSale.setSupplyRelatedSkuId(orderItem.getSupplyRelatedSkuId());
        tradeAfterSaleMapper.insert(afterSale);
        // 更新交易订单项的售后状态
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleCreate(orderItem.getId(), orderItem.getOrderId(), afterSale.getId());
        // 记录售后日志
        saveAfterSaleLog(afterSale.getId(), AfterSaleOperateTypeEnum.BUYER_CREATE, AfterSaleStatusEnum.NONE.getStatus(), AfterSaleStatusEnum.APPLY.getStatus(), null);
        // 事务提交后再发送站内信
        TransactionUtils.afterCommit(() -> {
            sendAfterSaleCreatedMessageAsync(afterSale);
            return null;
        });
        return afterSale;
    }

    @Async
    public void sendAfterSaleCreatedMessageAsync(AfterSaleDO afterSale) {
        // 用户申请退款，给所属商家发送站内信
        List<ShopAdminRespDTO> adminRespDTOS = shopUserApi.getShopAdminListByShopId(afterSale.getShopId());
        if (CollUtil.isEmpty(adminRespDTOS)) {
            log.warn("[sendAfterSaleCreatedMessageAsync][afterSale({}) 发送站内信时，未查询到店铺({})的管理员]", afterSale.getId(), afterSale.getShopId());
            return;
        }
        adminRespDTOS.forEach(adminRespDTO -> {
            Map<String, Object> templateParams = new HashMap<>();
            templateParams.put("no", afterSale.getNo());
            templateParams.put("orderNo", afterSale.getOrderNo());
            templateParams.put("spuName", afterSale.getSpuName());
            if (adminRespDTO.getAdminUserId() != null && adminRespDTO.getAdminUserId() > 0) {
                notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
                        .setUserId(adminRespDTO.getAdminUserId())
                        .setTemplateCode(TradeNotifySceneEnum.ORDER_AFTER_SALE_CREATE.getTemplateCode())
                        .setTemplateParams(templateParams));
            }
            if (adminRespDTO.getMemberUserId() != null && adminRespDTO.getMemberUserId() > 0) {
                notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()
                        .setUserId(adminRespDTO.getMemberUserId())
                        .setTemplateCode(TradeNotifySceneEnum.ORDER_AFTER_SALE_CREATE.getTemplateCode())
                        .setTemplateParams(templateParams));
            }
        });
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void agreeAfterSale(Long shopId, AfterSaleAgreeReqVO reqVO) {
        if (reqVO.getId() != null && reqVO.getId() > 0) {
            AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectByIdAndShopId(reqVO.getId(), shopId);
            doAgreeAfterSale(reqVO, afterSaleDO);
        } else {
            List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndShopId(reqVO.getOrderId(), shopId);
            Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
            list.forEach(afterSale -> doAgreeAfterSale(reqVO, afterSale));
        }
    }

    private void doAgreeAfterSale(AfterSaleAgreeReqVO reqVO, AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单是否可审核（同意售后、拒绝售后），因为可能存在多次退款申请，非审核状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) {
            log.warn("[doAgreeAfterSale][售后单({}) 不可审核，因为不处于【申请中】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        afterSaleDO.setAuditUserId(getLoginUserId());
        afterSaleDO.setAuditTime(LocalDateTime.now());
        // 有寄送地址，这获取省市区县
        if (reqVO.getDeliveryAreaId() != null && reqVO.getDeliveryAreaId() > 0) {
            afterSaleDO.setDeliveryName(reqVO.getDeliveryName());
            afterSaleDO.setDeliveryMobile(reqVO.getDeliveryMobile());
            Integer cityId = RegionUtils.getRegionParentId(RegionDataSet.ONLY_LATEST, reqVO.getDeliveryAreaId());
            Integer provinceId = RegionUtils.getRegionParentId(RegionDataSet.ONLY_LATEST, cityId);
            afterSaleDO.setDeliveryProvinceId(provinceId);
            afterSaleDO.setDeliveryCityId(cityId);
            afterSaleDO.setDeliveryAreaId(reqVO.getDeliveryAreaId());
            afterSaleDO.setDeliveryDetailAddress(reqVO.getDeliveryDetailAddress());
        }
        // 更新售后单的状态
        // 情况一：退款：标记为 WAIT_REFUND 状态。后续等退款发起成功后，在标记为 COMPLETE 状态
        // 情况二：退货退款：需要等用户退货后，才能发起退款
        boolean onlyRefund = afterSaleDO.getWay().equals(AfterSaleWayEnum.REFUND.getWay());
        Integer newStatus = onlyRefund ? AfterSaleStatusEnum.WAIT_REFUND.getStatus() : AfterSaleStatusEnum.SELLER_AGREE.getStatus();
        afterSaleDO.setStatus(newStatus);
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.APPLY.getStatus(), afterSaleDO);
        // 同步发起第三方供应链售后申请
        createSupplyAfterSaleApplyAsync(afterSaleDO);
        // 记录售后日志
        String address;
        if (afterSaleDO.getDeliveryAreaId() != null && afterSaleDO.getDeliveryAreaId() > 0) {
            address = RegionUtils.formatRegionName(RegionDataSet.ONLY_LATEST, reqVO.getDeliveryAreaId(), "") + afterSaleDO.getDeliveryDetailAddress();
        } else {
            address = "无";
        }
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.SELLER_AGREE_APPLY, afterSaleDO.getStatus(), newStatus, MapUtil.<String, Object>builder().put("deliveryAddress", address).build());
        // 更新交易订单项的售后状态
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleDoing(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId(), afterSaleDO.getStatus(), newStatus);
        TransactionUtils.afterCommit(() -> {
            // 卖家同意退款，给所属用户发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSaleDO, TradeNotifySceneEnum.ORDER_AFTER_SALE_AGREE);
            if (onlyRefund) {
                // 自动发起平台退款
                afterSaleDO.setStatus(newStatus);
                doRefundAfterSale(afterSaleDO);
            }
            return null;
        });
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void disagreeAfterSale(Long shopId, AfterSaleDisagreeReqVO reqVO) {
        // 校验售后单存在，并状态未审核
        if (reqVO.getId() != null && reqVO.getId() > 0) {
            AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectByIdAndShopId(reqVO.getId(), shopId);
            doDisagreeAfterSale(reqVO, afterSaleDO);
        } else {
            List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndShopId(reqVO.getOrderId(), shopId);
            Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
            list.forEach(afterSale -> doDisagreeAfterSale(reqVO, afterSale));
        }
    }

    private void doDisagreeAfterSale(AfterSaleDisagreeReqVO reqVO, AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单是否可审核（同意售后、拒绝售后），因为可能存在多次退款申请，非审核状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) {
            log.warn("[doDisagreeAfterSale][售后单({}) 不可审核，因为不处于【申请中】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        // 更新售后单的状态
        Integer newStatus = AfterSaleStatusEnum.SELLER_DISAGREE.getStatus();
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO().setStatus(newStatus)
                .setAuditUserId(getLoginUserId())
                .setAuditTime(LocalDateTime.now())
                .setAuditReason(reqVO.getAuditReason()));
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.SELLER_DISAGREE_APPLY, afterSaleDO.getStatus(), newStatus, null);
        // 更新交易订单项的售后状态为【未申请】
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId());
        TransactionUtils.afterCommit(() -> {
            // 卖家拒绝退款，给所属用户发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSaleDO, TradeNotifySceneEnum.ORDER_AFTER_SALE_DISAGREE);
            return null;
        });
    }

    private void updateAfterSaleStatus(Long id, Integer status, AfterSaleDO updateObj) {
        int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj);
        if (updateCount == 0) {
            throw exception(AFTER_SALE_UPDATE_STATUS_FAIL);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO reqVO) {
        // 校验售后单存在，并状态未退货
        if (reqVO.getOrderId() != null && reqVO.getOrderId() > 0) {
            List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndUserId(reqVO.getOrderId(), userId);
            Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
            list.forEach(afterSale -> doDeliveryAfterSale(reqVO, afterSale));
        } else {
            AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectByIdAndUserId(reqVO.getId(), userId);
            doDeliveryAfterSale(reqVO, afterSaleDO);
        }
    }

    private void doDeliveryAfterSale(AppAfterSaleDeliveryReqVO reqVO, AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单存在，并状态未退货，因为可能存在多次退款申请，非卖家同意退款状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.SELLER_AGREE.getStatus())) {
            log.warn("[doDeliveryAfterSale][售后单({}) 不可发货，因为不处于【卖家同意退款】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        DeliveryExpressDO expressDO = deliveryExpressService.validateDeliveryExpress(reqVO.getLogisticsId());
        long expressId = checkExpressId(afterSaleDO, expressDO);
        // 更新售后单的物流信息
        Integer newStatus = AfterSaleStatusEnum.BUYER_DELIVERY.getStatus();
        AfterSaleDO updateObj = new AfterSaleDO()
                .setStatus(newStatus)
                .setLogisticsId(reqVO.getLogisticsId())
                .setLogisticsNo(reqVO.getLogisticsNo())
                .setLogisticsDescription(reqVO.getLogisticsDescription())
                .setLogisticsPicUrls(reqVO.getLogisticsPicUrls())
                .setDeliveryTime(LocalDateTime.now());
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.SELLER_AGREE.getStatus(), updateObj);
        // 更新交易订单项的售后状态
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleDoing(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId(), afterSaleDO.getStatus(), newStatus);
        // 同步发起第三方供应链退换货填写运单号
        updateObj.setId(afterSaleDO.getId());
        updateObj.setSupplyRelatedNo(afterSaleDO.getSupplyRelatedNo());
        createSupplyAfterSaleExpress(updateObj, expressId);
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.BUYER_DELIVERY, afterSaleDO.getStatus(), newStatus, MapUtil.<String, Object>builder().put("deliveryName", expressDO.getName()).put("logisticsNo", reqVO.getLogisticsNo()).build());
        TransactionUtils.afterCommit(() -> {
            // 用户寄回退款货物，给同意售后的商家发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSaleDO, TradeNotifySceneEnum.ORDER_AFTER_SALE_BUYER_DELIVERY);
            return null;
        });
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void receiveAfterSale(Long shopId, Long id) {
        // 校验售后单存在，并且状态为买家已寄回货物
        AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectByIdAndShopId(id, shopId);
        doReceiveAfterSale(afterSaleDO);
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void receiveAfterSaleByOrder(Long shopId, Long orderId) {
        // 校验售后单存在，并且状态为买家已寄回货物
        List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndShopId(orderId, shopId);
        Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
        list.forEach(this::doReceiveAfterSale);
    }

    private void doReceiveAfterSale(AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单是否可收货，即处于买家已发货，因为可能存在多次退款申请，非买家已发货状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
            log.warn("[doReceiveAfterSale][售后单({}) 不可发货，因为不处于【买家已发货】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        // 更新售后单的状态
        Integer newStatus = AfterSaleStatusEnum.WAIT_REFUND.getStatus();
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
                .setStatus(newStatus).setReceiveTime(LocalDateTime.now()));
        // 更新交易订单项的售后状态
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleDoing(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId(), afterSaleDO.getStatus(), newStatus);
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.SELLER_AGREE_RECEIVE, afterSaleDO.getStatus(), newStatus, null);
        TransactionUtils.afterCommit(() -> {
            // 商家收到退款货物，给所属用户发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSaleDO, TradeNotifySceneEnum.ORDER_AFTER_SALE_SELLER_RECEIVE);
            // 自动发起平台退款
            afterSaleDO.setStatus(newStatus);
            doRefundAfterSale(afterSaleDO);
            return null;
        });
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void refuseAfterSale(Long shopId, AfterSaleRefuseReqVO reqVO) {
        // 校验售后单存在，并且状态为买家已寄回货物
        if (reqVO.getOrderId() != null && reqVO.getOrderId() > 0) {
            List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndShopId(reqVO.getOrderId(), shopId);
            Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
            list.forEach(afterSale -> doRefuseAfterSale(reqVO, afterSale));
        } else {
            AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectByIdAndShopId(reqVO.getId(), shopId);
            doRefuseAfterSale(reqVO, afterSaleDO);
        }
    }

    private void doRefuseAfterSale(AfterSaleRefuseReqVO reqVO, AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单是否可收货，即处于买家已发货，因为可能存在多次退款申请，非买家已发货状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
            log.warn("[doRefuseAfterSale][售后单({}) 不可发货，因为不处于【买家已发货】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        // 更新售后单的状态
        Integer newStatus = AfterSaleStatusEnum.SELLER_REFUSE.getStatus();
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
                .setStatus(newStatus).setReceiveTime(LocalDateTime.now())
                .setReceiveReason(reqVO.getRefuseMemo()));
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.SELLER_DISAGREE_RECEIVE, afterSaleDO.getStatus(), newStatus, MapUtil.of("reason", reqVO.getRefuseMemo()));
        // 更新交易订单项的售后状态为【未申请】
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId());
        TransactionUtils.afterCommit(() -> {
            // 商家拒收退款货物，给所属用户发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSaleDO, TradeNotifySceneEnum.ORDER_AFTER_SALE_SELLER_RECEIVE);
            return null;
        });
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void refundAfterSale(Long id) {
        AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectById(id);
        doRefundAfterSale(afterSaleDO);
    }

    @Override
    @DataPermission(enable = false)
    @Transactional(rollbackFor = Exception.class)
    public void refundAfterSaleByOrder(Long orderId) {
        List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderId(orderId);
        Assertions.notEmpty(list, AFTER_SALE_NOT_FOUND.getMsg());
        for (AfterSaleDO item : list) {
            doRefundAfterSale(item);
        }
    }

    private void doRefundAfterSale(AfterSaleDO afterSaleDO) {
        if (afterSaleDO == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        // 校验售后单的状态，并且状态为等待平台退款，因为可能存在多次退款申请，非等待平台退款状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.WAIT_REFUND.getStatus())) {
            log.warn("[doRefundAfterSale][售后单({}) 不可发货，因为不处于【等待平台退款】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        // 特殊：这里状态不变，最终由 updateAfterSaleRefunded 处理，真正退款完成后才能更新为【已完成】！！！
        updateAfterSaleStatus(afterSaleDO.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO()
                .setStatus(afterSaleDO.getStatus()).setRefundTime(LocalDateTime.now()));
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.PLATFORM_REFUND, afterSaleDO.getStatus(), afterSaleDO.getStatus(), null);
        // 更新交易订单项的售后状态
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleDoing(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId(), afterSaleDO.getStatus(), afterSaleDO.getStatus());
        // 发起平台退款
        createRefund(afterSaleDO);
    }

    private void createRefund(AfterSaleDO afterSale) {
        TradeOrderDO tradeOrderDO = tradeOrderQueryService.getOrderByNo(afterSale.getOrderNo());
        // 创建退款单
        PayRefundCreateDTO createDTO = new PayRefundCreateDTO();
        createDTO.setTradeNo(afterSale.getNo());
        createDTO.setPayNo(tradeOrderDO.getPayNo());
        createDTO.setRefundPrice(afterSale.getRefundPrice());
        createDTO.setUserIp(getClientIP());
        createDTO.setUserUa(getUserAgent());
        String reason = StrUtil.format("购买的【{}】退款", afterSale.getSpuName());
        if (StrUtil.isNotBlank(afterSale.getApplyReason())) {
            reason += "，" + afterSale.getApplyReason();
        }
        createDTO.setReason(reason);
        Long refundId = payRefundApi.createRefund(createDTO);
        // 更新售后单的退款单号
        AfterSaleDO updateObj = new AfterSaleDO();
        updateObj.setId(afterSale.getId());
        updateObj.setPayRefundId(refundId);
        tradeAfterSaleMapper.updateById(updateObj);
        // 事务提交后再发送站内信
        TransactionUtils.afterCommit(() -> {
            // 等待平台退款，给所属用户发送站内信
            sendNotifyMessageWhenAfterSaleAsync(afterSale, TradeNotifySceneEnum.ORDER_AFTER_SALE_REFUND);
            return null;
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAfterSaleRefunded(String no) {
        // 1. 校验售后单的状态，并状态待退款
        AfterSaleDO afterSale = tradeAfterSaleMapper.selectByNo(no);
        if (afterSale == null) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        Assertions.equals(afterSale.getStatus(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), "退款失败，售后单状态不是【待退款】");
        // 2. 校验退款单
        PayRefundVO refundVO = validatePayRefund(afterSale);
        // 3. 处理退款结果
        if (UnifiedRefundStatusEnum.isSuccess(refundVO.getStatus())) {
            // 【情况一：退款成功】
            AfterSaleDO afterSaleDO = new AfterSaleDO();
            afterSaleDO.setStatus(AfterSaleStatusEnum.COMPLETE.getStatus());
            afterSaleDO.setRefundTime(LocalDateTime.now());
            updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), afterSaleDO);
            // 记录售后日志
            saveAfterSaleLog(afterSale.getId(), AfterSaleOperateTypeEnum.SYSTEM_REFUND_SUCCESS, afterSale.getStatus(), AfterSaleStatusEnum.COMPLETE.getStatus(), null);
            // 更新交易订单项的售后状态为【已完成】
            tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getOrderId(), afterSale.getRefundPrice());
            // 【情况二：退款失败】
        } else if (UnifiedRefundStatusEnum.isFailure(refundVO.getStatus())) {
            // 记录售后日志
            saveAfterSaleLog(afterSale.getId(), AfterSaleOperateTypeEnum.SYSTEM_REFUND_FAIL, afterSale.getStatus(), afterSale.getStatus(), null);
        }
    }

    /**
     * 校验退款单的合法性
     *
     * @param afterSale 售后单
     * @return 退款单
     */
    private PayRefundVO validatePayRefund(AfterSaleDO afterSale) {
        // 1. 校验退款单是否存在
        PayRefundVO refundVO = payRefundApi.getRefund(afterSale.getPayRefundId());
        if (refundVO == null) {
            log.error("[validatePayRefund][afterSale({}) payRefundId({}) 不存在，请进行处理！]", afterSale.getId(), afterSale.getPayRefundId());
            throw new KnownServiceException("交易订单更新支付订单退款状态失败，原因：退款单不存在");
        }
        // 2.1 校验退款单无退款结果（成功、失败）
        if (!UnifiedRefundStatusEnum.isSuccess(refundVO.getStatus())
            && !UnifiedRefundStatusEnum.isFailure(refundVO.getStatus())) {
            log.error("[validatePayRefund][afterSale({}) payRefundId({}) 无退款结果，请进行处理！refundVO 数据是：{}]", afterSale.getId(), afterSale.getPayRefundId(), JsonUtils.toJsonString(refundVO));
            throw new KnownServiceException("退款失败，退款单未退款");
        }
        // 2.2 校验退款金额一致
        if (ObjectUtil.notEqual(refundVO.getRefundPrice(), afterSale.getRefundPrice())) {
            log.error("[validatePayRefund][afterSale({}) payRefundId({}) 退款金额不匹配，请进行处理！afterSale 数据是：{}，refundVO 数据是：{}]", afterSale.getId(), afterSale.getPayRefundId(), JsonUtils.toJsonString(afterSale), JsonUtils.toJsonString(refundVO));
            throw exception(AFTER_SALE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
        }
        // 2.3 校验退款订单匹配（二次）
        if (ObjectUtil.notEqual(refundVO.getRefundNo(), afterSale.getNo())) {
            log.error("[validatePayRefund][afterSale({}) 退款单不匹配({})，请进行处理！退款单数据是：{}]", afterSale.getNo(), refundVO.getRefundNo(), JsonUtils.toJsonString(refundVO));
            throw new KnownServiceException("退款失败，退款单不匹配");
        }
        return refundVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelAfterSale(Long userId, Long id) {
        // 校验售后单的状态，并状态待退款
        AfterSaleDO afterSaleDO = tradeAfterSaleMapper.selectById(id);
        doCancelAfterSale(afterSaleDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelAfterSaleByOrder(Long userId, Long orderId) {
        List<AfterSaleDO> list = tradeAfterSaleMapper.selectByOrderIdAndUserId(orderId, userId);
        if (CollUtil.isEmpty(list)) {
            throw exception(AFTER_SALE_NOT_FOUND);
        }
        for (AfterSaleDO afterSaleDO : list) {
            doCancelAfterSale(afterSaleDO);
        }
    }

    private void doCancelAfterSale(AfterSaleDO afterSaleDO) {
        Assertions.notNull(afterSaleDO, AFTER_SALE_NOT_FOUND.getMsg());
        // 校验售后单的状态，因为可能存在多次退款申请，非申请中状态则忽略
        if (!Objects.equals(afterSaleDO.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) {
            log.warn("[doCancelAfterSale][售后单({}) 不可取消，因为不处于【申请中】状态({})]", afterSaleDO.getId(), afterSaleDO.getStatus());
            return;
        }
        // 更新售后单的状态为【已取消】
        updateAfterSaleStatus(afterSaleDO.getId(), afterSaleDO.getStatus(), new AfterSaleDO()
                .setStatus(AfterSaleStatusEnum.BUYER_CANCEL.getStatus()));
        // 记录售后日志
        saveAfterSaleLog(afterSaleDO.getId(), AfterSaleOperateTypeEnum.BUYER_CANCEL, afterSaleDO.getStatus(), AfterSaleStatusEnum.BUYER_CANCEL.getStatus(), null);
        // 更新交易订单项的售后状态为【未申请】
        tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSaleDO.getOrderItemId(), afterSaleDO.getOrderId());
        TransactionUtils.afterCommit(() -> {
            // 用户取消退款，给所属商家发送站内信
            sendAfterSaleCanceledMessageAsync(afterSaleDO);
            return null;
        });
    }

    @Async
    public void sendAfterSaleCanceledMessageAsync(AfterSaleDO afterSaleDO) {
        List<ShopAdminRespDTO> adminRespDTOS = shopUserApi.getShopAdminListByShopId(afterSaleDO.getShopId());
        if (CollUtil.isNotEmpty(adminRespDTOS)) {
            adminRespDTOS.forEach(adminRespDTO -> {
                Map<String, Object> templateParams = new HashMap<>();
                templateParams.put("no", afterSaleDO.getNo());
                templateParams.put("orderNo", afterSaleDO.getOrderNo());
                templateParams.put("spuName", afterSaleDO.getSpuName());
                if (adminRespDTO.getAdminUserId() != null && adminRespDTO.getAdminUserId() > 0) {
                    notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
                            .setUserId(adminRespDTO.getAdminUserId())
                            .setTemplateCode(TradeNotifySceneEnum.ORDER_AFTER_SALE_CANCEL.getTemplateCode())
                            .setTemplateParams(templateParams));
                }
                if (adminRespDTO.getMemberUserId() != null && adminRespDTO.getMemberUserId() > 0) {
                    notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()
                            .setUserId(adminRespDTO.getMemberUserId())
                            .setTemplateCode(TradeNotifySceneEnum.ORDER_AFTER_SALE_CANCEL.getTemplateCode())
                            .setTemplateParams(templateParams));
                }
            });
        }
    }

    @Override
    public Integer getApplyingAfterSaleCountByUserId(Long userId, boolean fullOrder) {
        Long count;
        if (fullOrder) {
            count = tradeAfterSaleMapper.selectCountForUserDistinctByOrderId(userId, AfterSaleStatusEnum.APPLYING_STATUSES);
        } else {
            count = tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES);
        }
        return count == null ? 0 : count.intValue();
    }

    @Override
    public Integer getApplyingAfterSaleCountByShopId(Long shopId, boolean fullOrder) {
        Long count;
        if (fullOrder) {
            count = tradeAfterSaleMapper.selectCountForShopDistinctByOrderId(shopId, AfterSaleStatusEnum.APPLYING_STATUSES);
        } else {
            count = tradeAfterSaleMapper.selectCountByShopIdIdAndStatus(shopId, AfterSaleStatusEnum.APPLYING_STATUSES);
        }
        return count == null ? 0 : count.intValue();
    }

    @Async
    public void sendNotifyMessageWhenAfterSaleAsync(AfterSaleDO afterSaleDO, TradeNotifySceneEnum orderAfterSaleAgree) {
        try {
            Map<String, Object> templateParams = new HashMap<>();
            templateParams.put("no", afterSaleDO.getNo());
            templateParams.put("orderNo", afterSaleDO.getOrderNo());
            templateParams.put("spuName", afterSaleDO.getSpuName());
            notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()
                    .setUserId(afterSaleDO.getUserId())
                    .setTemplateCode(orderAfterSaleAgree.getTemplateCode())
                    .setTemplateParams(templateParams));
        } catch (Exception e) {
            log.error("[sendNotifyMessageWhenAfterSaleAsync][afterSaleDO({}) 发送站内信出错]", JsonUtils.toJsonString(afterSaleDO), e);
        }
    }

    @Async
    public void createSupplyAfterSaleApplyAsync(AfterSaleDO afterSaleDO) {
        String supplyRelatedOrders = afterSaleDO.getSupplyRelatedOrders();
        if (!JsonUtils.isJson(supplyRelatedOrders)) {
            return;
        }
        List<ZXHXOrderSubmitRespDTO> supplyRelatedOrdersList = JsonUtils.parseArray(supplyRelatedOrders, ZXHXOrderSubmitRespDTO.class);
        if (CollUtil.isEmpty(supplyRelatedOrdersList)) {
            return;
        }
        // 下单时一个 SKU 对应一个订单项，所以直接取第一个即可
        ZXHXAfterSaleSubmitRespDTO afterSaleSubmitRespDTO = ZXHXApiClientFactory.tradeClient().submitAfterSale(buildAfterSaleSubmitReqDTO(afterSaleDO, supplyRelatedOrdersList.get(0)));
        // TODO 退货退款的情况需要获取卖家地址来给买家寄货
        AfterSaleDO updateObj = new AfterSaleDO();
        updateObj.setId(afterSaleDO.getId());
        updateObj.setSupplyRelatedNo(afterSaleSubmitRespDTO.getServiceSn());
        tradeAfterSaleMapper.updateById(updateObj);
    }

    @Nonnull
    private ZXHXAfterSaleSubmitReqDTO buildAfterSaleSubmitReqDTO(AfterSaleDO afterSaleDO, ZXHXOrderSubmitRespDTO orderSubmitRespDTO) {
        ZXHXAfterSaleSubmitReqDTO afterSaleSubmitReqDTO = new ZXHXAfterSaleSubmitReqDTO();
        if (AfterSaleWayEnum.RETURN_AND_REFUND.getWay().equals(afterSaleDO.getWay())) {
            afterSaleSubmitReqDTO.setServiceType(ZXHXAfterSaleType.RETURN_AND_REFUND.getValue());
        } else {
            afterSaleSubmitReqDTO.setServiceType(ZXHXAfterSaleType.REFUND_ONLY.getValue());
        }
        afterSaleSubmitReqDTO.setOrderSn(orderSubmitRespDTO.getOrderSn());
        afterSaleSubmitReqDTO.setSkuId(afterSaleDO.getSupplyRelatedSkuId());
        afterSaleSubmitReqDTO.setSkuNum(afterSaleDO.getCount());
        if (orderSubmitRespDTO.getPayPrice() > 0) {
            afterSaleSubmitReqDTO.setAmountMoney(String.valueOf(orderSubmitRespDTO.getPayPrice()));
        } else {
            afterSaleSubmitReqDTO.setAmountMoney(String.valueOf(0));
        }
        afterSaleSubmitReqDTO.setImages(afterSaleDO.getApplyPicUrls());
        afterSaleSubmitReqDTO.setRemark(afterSaleDO.getApplyReason());
        return afterSaleSubmitReqDTO;
    }

    private long checkExpressId(AfterSaleDO afterSaleDO, DeliveryExpressDO expressDO) {
        List<ZXHXExpressItemRespDTO> expressItemRespDTOS = ZXHXApiClientFactory.commonClient().getExpress();
        Assertions.notEmpty(expressItemRespDTOS, "支持的快递公司信息获取失败");
        long expressId = 0L;
        for (ZXHXExpressItemRespDTO expressItemRespDTO : expressItemRespDTOS) {
            if (Objects.equals(expressItemRespDTO.getShortName(), expressDO.getCode())) {
                expressId = expressItemRespDTO.getId();
                break;
            }
        }
        if (expressId == 0L) {
            expressId = expressDO.getSupplyRelatedId();
        }
        Assertions.isTrue(expressId > 0, "不支持的快递公司：" + afterSaleDO.getLogisticsNo());
        return expressId;
    }

    private void createSupplyAfterSaleExpress(AfterSaleDO afterSaleDO, long expressId) {
        String supplyRelatedNo = afterSaleDO.getSupplyRelatedNo();
        if (StrUtil.isBlank(supplyRelatedNo)) {
            return;
        }
        ZXHXApiClientFactory.tradeClient().expressSubmit(supplyRelatedNo, expressId, afterSaleDO.getLogisticsNo());
    }

    private void saveAfterSaleLog(Long afterSaleId, AfterSaleOperateTypeEnum operateType, Integer beforeStatus, Integer afterStatus, @Nullable Map<String, Object> extra) {
        log.debug("[saveAfterSaleLog({})] operateType({}) beforeStatus({}) afterStatus({}) extra({})", afterSaleId, operateType, beforeStatus, afterStatus, extra);
        // 1.0 售后信息
        if (afterSaleId == null || afterSaleId <= 0) { // 如果未设置，只有注解，说明不需要记录日志
            return;
        }
        try {
            // 1.1 操作用户
            Integer userType = ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM);
            Long userId = ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM);
            Map<String, Object> extraMap = ObjectUtil.defaultIfNull(extra, Map.of());
            String content = StrUtil.format(operateType.getContent(), extraMap);
            // 2. 记录日志
            AfterSaleLogCreateReqBO createBO = new AfterSaleLogCreateReqBO();
            createBO.setUserId(userId);
            createBO.setUserType(userType);
            createBO.setAfterSaleId(afterSaleId);
            createBO.setBeforeStatus(beforeStatus);
            createBO.setAfterStatus(afterStatus);
            createBO.setOperateType(operateType.getType());
            createBO.setContent(content);
            afterSaleLogService.createAfterSaleLog(createBO);
        } catch (Exception e) {
            log.error("[saveAfterSaleLog({}) 日志记录错误]", afterSaleId, e);
        }
    }

}
